<template>
    <view class="uploadCom">
        <view class="items center" v-for="(item, index) in fileList" :key="index">
            <!-- 图片 -->
            <u-image v-if="item.isImg" width="160rpx" height="160rpx" :src="item.displayUrl" @click="onPreviewShow(item, index)" mode="aspectFit"></u-image>

            <!-- 文件 -->
            <view v-else @click="onDownload(item, index)">
                <i class="exticon" :class="item.icon" style="font-size: 100rpx"></i>
            </view>

            <!-- 删除 -->
            <u-icon v-if="!readOnly && !disabled" class="delete" color="#e45656" :size="25" name="close-circle-fill" @click.native.stop="onDelete(index)"></u-icon>
        </view>

        <!-- 真上传按钮 -->
        <view class="upload" v-if="!disabled && fileList.length < limit" v-show="!readOnly">
            <lsj-upload ref="lsjUploadRef" height="170rpx" :debug="false" :instantly="true" :childId="id" :count="1000" :option="options" @uploadEnd="onUploadEnd" @change="onChange">
                <view class="add">
                    <u-icon name="plus" :size="40"></u-icon>
                </view>
            </lsj-upload>
        </view>

        <!-- 假上传按钮，用于处理当点击图片预览时，上传按钮还在，但是没有任何事件 -->
        <view v-if="!disabled && fileList.length < limit" v-show="readOnly">
            <view class="upload">
                <view class="add">
                    <u-icon name="plus" :size="40"></u-icon>
                </view>
            </view>
        </view>

        <!-- 预览 -->
        <ImgShow :list="previewImgs" ref="ImgShowRef" @hide="onPreviewHide()"></ImgShow>

        <u-button type="primary" size="small" v-if="!readOnly && !disabled" @click="onSave">保存</u-button>
    </view>
</template>

<script>
import Config from "@/gx/Config";
import gx from "../../gx/gx";
import Enums from "../../gx/Enums";
import extIcon from "../../static/fonts/exticonfont/extIcon";
export default {
    name: "Upload",
    data() {
        return {
            fileList: [],
            imageExts: ["png", "jpg", "jpeg", "gif", "bmp", "tiff", "pjp", "jfif", "svg", "xbm", "dib", "jxl", "svgz", "webp", "ico", "tif", "pjpeg", "avif"], //图片类型的扩展名
            fileExts: ["doc", "xls", "ppt", "pdf", "docx", "xlsx", "pptx"],
            options: {}, //lsj-upload 需要的参数
            extIcon: extIcon, //文件图标对应的内容
            previewImgs: [], //预览图片的集合
            readOnly: false, //是否只读
        };
    },
    model: {
        //event:什么时候触发v-model行为，对于uni-app，必须写input
        event: "input",
        // 定义传递给v-model的那个变量，绑定到哪个属性值上
        prop: "modelValue",
    },
    props: {
        //对应v-model双向绑定的值
        modelValue: {
            type: Array,
            default() {
                return [];
            },
        },

        //上传组件id
        id: {
            type: String,
            require: true,
        },

        //限制上传文件数量
        limit: {
            type: Number,
            default: 9,
        },

        //是否为只能上传图片，此功能暂时处理不了，原因查看onChange方法
        onlyImg: {
            type: Boolean,
            default: false,
        },

        //dom重排刷新间隔时间
        setTimeoutNum: {
            type: Number,
            default: 1000,
        },

        //是否禁用
        disabled: {
            type: Boolean,
            default: false,
        },
    },
    created() {
        //组件加载时就构建出 options 对象。对于七牛上传时的文件名，在 lsj-upload 组件的uploadFile.html中处理的
        if (Config.UploadPosition == Enums.UploadPosition.本地) {
            let _token = uni.getStorageSync(Config.TokenKey);
            this.options = {
                url: Config.ApiUrl + "/Upload",
                name: "file",
                header: {
                    Authorization: "bearer " + _token.access_token,
                },
                formData: {},
            };
        } else if (Config.UploadPosition == Enums.UploadPosition.远程) {
            let _token = uni.getStorageSync(Config.QiniuTokenKey);

            this.options = {
                url: _token.bucketArea,
                name: "file",
                header: {
                    ContentType: "multipart/form-data",
                },
                formData: {
                    token: _token.token,
                    domain: _token.domain,
                },
            };
        }
    },
    mounted() {
        //定义一个全局事件，用来刷新dom
        uni.$on("refreshUpload", () => {
            setTimeout(() => {
                if (!this.$gx.IsEmpty(this.$refs) && !this.$gx.IsEmpty(this.$refs.lsjUploadRef)) {
                    this.$refs.lsjUploadRef.show();
                }
            }, this.setTimeoutNum);
        });

        this.formatFiles();
    },
    watch: {
        modelValue: {
            handler(newVal, oldVal) {
                this.fileList = newVal;
                this.formatFiles();
            },
            immediate: true, //首次加载时就要执行
        },
    },
    methods: {
        //格式化数据，增加一些前端使用到的属性
        formatFiles() {
            for (let i = 0; i < this.modelValue.length; i++) {
                let item = this.modelValue[i];

                item.extName = item.fileName.replace(/.+\./, "");
                item.isImg =
                    this.imageExts.findIndex((x) => {
                        return x == item.extName;
                    }) > -1;
                if (item.isImg) {
                    if (Config.UploadPosition == Enums.UploadPosition.本地) {
                        item.displayUrl = Config.ApiUrl + item.url;
                    } else if (Config.UploadPosition == Enums.UploadPosition.远程) {
                        item.displayUrl = item.url;
                    } else {
                        item.displayUrl = "";
                    }
                } else {
                    item.icon = this.extIcon[item.extName] || this.extIcon["undefined"];
                }
            }
            uni.$emit("refreshUpload");
        },

        //选择文件触发，返回所有已选择文件Map集合
        onChange(mapData) {
            //TODO:原本是想通过这里处理上传的时的一些验证等功能，但现在处理不了
            /**
             * 原因：
             * 1、mapData中的数据，是包含所有上传的数据，即之前上传过的和本次上传的都会在里面
             * 2、this.list中不包含本次上传的文件
             * 3、在这里写return或return false也不能停止上传的功能
             */
        },

        //上传结束
        onUploadEnd(obj) {
            console.log(obj);
            if (obj.type == "success") {
                var res = null;
                if (Config.UploadPosition == Enums.UploadPosition.本地) {
                    res = gx.DeserializeObject(obj.responseText)?.data;
                } else if (Config.UploadPosition == Enums.UploadPosition.远程) {
                    var qiniuRes = gx.DeserializeObject(obj.responseText);
                    let _token = uni.getStorageSync(Config.QiniuTokenKey);
                    res = {
                        url: _token.domain + "/" + qiniuRes.key,
                        fileName: qiniuRes.key,
                    };
                }

                this.fileList.push(res);
                this.emitData();
            } else {
                throw new Error("上传失败！");
            }
        },

        //删除
        onDelete(index) {
            //TODO:这里删除时不对，当文件上传多个，超过6个时，就算是删除了一个，再点上传也不能上传了。需要把插件换成新版的
            this.fileList.splice(index, 1);
            this.emitData();
            this.$emit("onDelete", index);
        },

        //预览
        onPreviewShow(item, index) {
            //处理预览时，只把图片过滤出来，一次性可以预览完成
            let _list = gx.DeepCopy(this.fileList);

            let res = [];
            let cnt = 0;

            for (let i = 0; i < _list.length; i++) {
                let it = _list[i];
                if (it.isImg) {
                    res.push(it);
                } else {
                    if (i < index) {
                        cnt++;
                    }
                }
            }

            this.previewImgs = res;
            this.readOnly = true;
            this.$refs.ImgShowRef.show(index - cnt);
            this.$emit("onPreviewShow");
        },

        //预览关闭
        onPreviewHide() {
            this.readOnly = false;
            this.$emit("onPreviewHide");
        },

        //下载文件
        onDownload(item, index) {
            // #ifdef APP-PLUS
            uni.showLoading({ title: "开始下载并保存，请稍后！" });

            uni.downloadFile({
                url: item.url,
                success: (downRes) => {
                    if (downRes.statusCode === 200) {
                        uni.saveFile({
                            tempFilePath: downRes.tempFilePath,
                            success: (saveRes) => {
                                let fileInfo = this.$gx.GetUrlFileName(saveRes.savedFilePath);

                                let findIndex = this.fileExts.findIndex((x) => {
                                    return x === fileInfo.extName.toLowerCase();
                                });

                                if (findIndex != -1) {
                                    this.$app.Tips({ title: "正在打开文件...", icon: "none" });
                                    uni.openDocument({
                                        filePath: saveRes.savedFilePath,
                                        success: (res) => {},
                                        fail() {
                                            this.$app.Tips({ title: "打开失败！" });
                                        },
                                    });
                                } else {
                                    this.$app.Tips({ title: "保存成功！", icon: "none" });
                                }
                            },
                            fail() {
                                this.$app.Tips({ title: "保存失败！" });
                            },
                        });
                    }
                },
                fail() {
                    this.$app.Tips({ title: "保存失败！" });
                },
                complete() {
                    uni.hideLoading();
                },
            });
            // #endif

            // #ifdef H5
            console.error("H5不支持打开文件，请使用App！");
            // #endif
        },

        //回传数据
        emitData() {
            this.$emit("input", this.fileList);
            uni.$emit("refreshUpload");
        },

        //设置只读
        setReadOnly(flag) {
            this.readOnly = flag;
        },

        onSave() {
            this.$emit("close", this.fileList);
        },
    },
};
</script>

<style scoped>
.uploadCom {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}

.upload {
    float: left;
    width: 170rpx;
    height: 170rpx;
}

.add {
    width: 160rpx;
    height: 160rpx;
    border: 2rpx dashed #c0ccda;
    border-radius: 10rpx;
    display: flex;
    justify-content: center;
    align-items: center;
}

.items {
    width: 160rpx;
    height: 160rpx;
    margin-right: 15rpx;
    margin-bottom: 15rpx;
    border-radius: 10rpx;
    overflow: hidden;
    position: relative;
    border: 2rpx solid #c0ccda;
}

.center {
    display: flex;
    align-items: center;
    justify-content: center;
}

.delete {
    position: absolute;
    top: 0rpx;
    right: 0rpx;
}
</style>
